home *** CD-ROM | disk | FTP | other *** search
- /* ------------------------------------------------------------ */
- /*
- HTTrack Website Copier, Offline Browser for Windows and Unix
- Copyright (C) Xavier Roche and other contributors
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-
- Important notes:
-
- - We hereby ask people using this source NOT to use it in purpose of grabbing
- emails addresses, or collecting any other private information on persons.
- This would disgrace our work, and spoil the many hours we spent on it.
-
-
- Please visit our Website: http://www.httrack.com
- */
-
-
- /* ------------------------------------------------------------ */
- /* File: Subroutines */
- /* Author: Xavier Roche */
- /* ------------------------------------------------------------ */
-
- // Fichier librairie .c
-
- #include "htslib.h"
- #include "htsbauth.h"
-
- /* specific definitions */
- #include "htsbase.h"
- #include "htsnet.h"
- #include "htsbauth.h"
- #include "htsthread.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <sys/timeb.h>
- #include <fcntl.h>
- // pour utimbuf
- #if HTS_WIN
- #include <sys/utime.h>
- #else
- #if HTS_PLATFORM!=3
- #include <utime.h>
- #else
- #include <utime.h>
- #endif
- #endif
- /* END specific definitions */
-
-
-
- // DΘbuggage de contr⌠le
- #if HTS_DEBUG_CLOSESOCK
- #define _HTS_WIDE 1
- #endif
- #if HTS_WIDE_DEBUG
- #define _HTS_WIDE 1
- #endif
- #if _HTS_WIDE
- FILE* DEBUG_fp=NULL;
- #define DEBUG_W(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
- #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
- #endif
-
- /* variables globales */
- int _DEBUG_HEAD;
- FILE* ioinfo;
-
- /* dΘtection complΘmentaire */
- const char hts_detect[][32] = {
- "archive",
- "background",
- "dynsrc",
- "lowsrc",
- "src",
- "url",
- ""
- };
-
- /* dΘtection de mini-code javascript */
- /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
- const char hts_detect_js[][32] = {
- "onAbort",
- "onBlur",
- "onChange",
- "onClick",
- "onDblClick",
- "onDragDrop",
- "onError",
- "onFocus",
- "onKeyDown",
- "onKeyPress",
- "onKeyUp",
- "onLoad",
- "onMouseDown",
- "onMouseMove",
- "onMouseOut",
- "onMouseOver",
- "onMouseUp",
- "onMove",
- "onReset",
- "onResize",
- "onSelect",
- "onSubmit",
- "onUnload",
- ""
- };
-
- /* dΘtection "...URL=<url>" */
- const char hts_detectURL[][32] = {
- "content",
- ""
- };
-
- /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
- const char hts_detectandleave[][32] = {
- "action",
- ""
- };
-
- /* ne pas renommer les types renvoyΘs (couvent types inconnus) */
- const char hts_mime_keep[][32] = {
- "application/octet-stream",
- "text/plain",
- ""
- };
-
- /* types MIME */
- const char hts_mime[][2][32] = {
- {"application/acad","dwg"},
- {"application/arj","arj"},
- {"application/clariscad","ccad"},
- {"application/drafting","drw"},
- {"application/dxf","dxf"},
- {"application/excel","xl"},
- {"application/i-deas","unv"},
- {"application/iges","isg"},
- {"application/iges","iges"},
- {"application/mac-binhex40","hqx"},
- {"application/mac-compactpro","cpt"},
- {"application/msword","word"},
- {"application/msword","w6w"},
- {"application/msword","doc"},
- {"application/mswrite","wri"},
- /*{"application/octet-stream","dms"},*/
- /*{"application/octet-stream","lzh"},*/
- /*{"application/octet-stream","lha"},*/
- /*{"application/octet-stream","bin"},*/
- {"application/oda","oda"},
- {"application/pdf","pdf"},
- {"application/postscript","ai"},
- {"application/postscript","ps"},
- {"application/postscript","eps"},
- {"application/powerpoint","ppt"},
- {"application/pro_eng","prt"},
- {"application/pro_eng","part"},
- {"application/rtf","rtf"},
- {"application/set","set"},
- {"application/sla","stl"},
- {"application/smil","smi"},
- {"application/smil","smil"},
- {"application/smil","sml"},
- {"application/solids","sol"},
- {"application/STEP","stp"},
- {"application/STEP","step"},
- {"application/vda","vda"},
- {"application/x-authorware-map","aam"},
- {"application/x-authorware-seg","aas"},
- {"application/x-authorware-bin","aab"},
- {"application/x-cocoa","cco"},
- {"application/x-csh","csh"},
- {"application/x-director","dir"},
- {"application/x-director","dcr"},
- {"application/x-director","dxr"},
- {"application/x-mif","mif"},
- {"application/x-dvi","dvi"},
- {"application/x-gzip","gz"},
- {"application/x-gzip","gzip"},
- {"application/x-hdf","hdf"},
- {"application/x-javascript","js"},
- {"application/x-koan","skp"},
- {"application/x-koan","skd"},
- {"application/x-koan","skt"},
- {"application/x-koan","skm"},
- {"application/x-latex","latex"},
- {"application/x-netcdf","nc"},
- {"application/x-netcdf","cdf"},
- /* {"application/x-sh","sh"}, */
- /* {"application/x-csh","csh"}, */
- /* {"application/x-ksh","ksh"}, */
- {"application/x-shar","shar"},
- {"application/x-stuffit","sit"},
- {"application/x-tcl","tcl"},
- {"application/x-tex","tex"},
- {"application/x-texinfo","texinfo"},
- {"application/x-texinfo","texi"},
- {"application/x-troff","t"},
- {"application/x-troff","tr"},
- {"application/x-troff","roff"},
- {"application/x-troff-man","man"},
- {"application/x-troff-me","ms"},
- {"application/x-wais-source","src"},
- {"application/zip","zip"},
- {"application/x-bcpio","bcpio"},
- {"application/x-cdlink","vcd"},
- {"application/x-cpio","cpio"},
- {"application/x-gtar","tgz"},
- {"application/x-gtar","gtar"},
- {"application/x-shar","shar"},
- {"application/x-shockwave-flash","swf"},
- {"application/x-sv4cpio","sv4cpio"},
- {"application/x-sv4crc","sv4crc"},
- {"application/x-tar","tar"},
- {"application/x-ustar","ustar"},
- {"application/x-winhelp","hlp"},
- {"audio/midi","mid"},
- {"audio/midi","midi"},
- {"audio/midi","kar"},
- {"audio/mpeg","mp3"},
- {"audio/mpeg","mpga"},
- {"audio/mpeg","mp2"},
- {"audio/basic","au"},
- {"audio/basic","snd"},
- {"audio/x-aiff","aif"},
- {"audio/x-aiff","aiff"},
- {"audio/x-aiff","aifc"},
- {"audio/x-pn-realaudio","ra"},
- {"audio/x-pn-realaudio","ram"},
- {"audio/x-pn-realaudio","rm"},
- {"audio/x-pn-realaudio-plugin","rpm"},
- {"audio/x-wav","wav"},
- {"chemical/x-pdb","pdb"},
- {"chemical/x-pdb","xyz"},
- {"drawing/x-dwf","dwf"},
- {"image/gif","gif"},
- {"image/ief","ief"},
- {"image/jpeg","jpg"},
- {"image/jpeg","jpe"},
- {"image/jpeg","jpeg"},
- {"image/pict","pict"},
- {"image/png","png"},
- {"image/tiff","tiff"},
- {"image/tiff","tif"},
- {"image/x-cmu-raster","ras"},
- {"image/x-freehand","fh4"},
- {"image/x-freehand","fh7"},
- {"image/x-freehand","fh5"},
- {"image/x-freehand","fhc"},
- {"image/x-freehand","fh"},
- {"image/x-portable-anymap","pnm"},
- {"image/x-portable-bitmap","pgm"},
- {"image/x-portable-pixmap","ppm"},
- {"image/x-rgb","rgb"},
- {"image/x-xbitmap","xbm"},
- {"image/x-xpixmap","xpm"},
- {"image/x-xwindowdump","xwd"},
- {"model/mesh","msh"},
- {"model/mesh","mesh"},
- {"model/mesh","silo"},
- {"multipart/x-zip","zip"},
- {"multipart/x-gzip","gzip"},
- {"text/css","css"},
- {"text/html","html"},
- {"text/html","htm"},
- {"text/plain","txt"},
- {"text/plain","g"},
- {"text/plain","h"},
- {"text/plain","c"},
- {"text/plain","cc"},
- {"text/plain","hh"},
- {"text/plain","m"},
- {"text/plain","f90"},
- {"text/richtext","rtx"},
- {"text/tab-separated-values","tsv"},
- {"text/x-setext","etx"},
- {"text/x-sgml","sgml"},
- {"text/x-sgml","sgm"},
- {"text/xml","xml"},
- {"text/xml","dtd"},
- {"video/mpeg","mpeg"},
- {"video/mpeg","mpg"},
- {"video/mpeg","mpe"},
- {"video/quicktime","qt"},
- {"video/quicktime","mov"},
- {"video/x-msvideo","avi"},
- {"video/x-sgi-movie","movie"},
- {"x-conference/x-cooltalk","ice"},
- /*{"application/x-httpd-cgi","cgi"},*/
- {"x-world/x-vrml","wrl"},
-
- {"*","class"},
-
- {"",""}};
-
-
-
- // conversion Θventuelle / vers antislash
- #if HTS_WIN
- char* antislash(char* s) {
- static char buff[HTS_URLMAXSIZE*2];
- static char* a;
- strcpy(buff,s);
- while(a=strchr(buff,'/')) *a='\\';
- return buff;
- }
- #endif
-
-
-
- // RΘcupΘration d'un fichier http sur le net.
- // Renvoie une adresse sur le bloc de mΘmoire, ou bien
- // NULL si un retour.msgeur (buffer retour.msg) est survenue.
- //
- // Une adresse de structure htsmsg peut Ωtre transmise pour
- // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ
- // en background
-
- htsblk httpget(char* url) {
- char adr[HTS_URLMAXSIZE*2]; // adresse
- char fil[HTS_URLMAXSIZE*2]; // chemin
-
- // sΘparer URL en adresse+chemin
- if (ident_url(url,adr,fil)==-1) {
- htsblk retour;
- bzero((char *)&retour, sizeof(htsblk)); // effacer
- // retour prΘdΘfini: erreur
- retour.adr=NULL;
- retour.size=0;
- retour.msg[0]='\0';
- retour.statuscode=-1;
- strcpy(retour.msg,"Error invalid URL");
- return retour;
- }
-
- return xhttpget(adr,fil);
- }
-
- // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
- // retour: socket
- int http_fopen(char* adr,char* fil,htsblk* retour) {
- // / GET, traiter en-tΩte
- return http_xfopen(0,1,1,NULL,adr,fil,retour);
- }
-
- // ouverture d'une liaison http, envoi d'une requΦte
- // mode: 0 GET 1 HEAD [2 POST]
- // treat: traiter header?
- // waitconnect: attendre le connect()
- // note: dans retour, on met les params du proxy
- int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
- //htsblk retour;
- //int bufl=TAILLE_BUFFER; // 8Ko de buffer
- T_SOC soc=INVALID_SOCKET;
- //char *p,*q;
-
- // retour prΘdΘfini: erreur
- if (retour) {
- retour->adr=NULL;
- retour->size=0;
- retour->msg[0]='\0';
- retour->statuscode=-5; // a priori erreur non fatale
- }
-
- #if HDEBUG
- printf("adr=%s\nfichier=%s\n",adr,fil);
- #endif
-
- // ouvrir liaison
- #if HDEBUG
- printf("CrΘation d'une socket sur %s\n",adr);
- #endif
-
- #if CNXDEBUG
- printf("..newhttp\n");
- #endif
-
- /* connexion */
- if (retour) {
- if ( (!(retour->req.proxy.active)) || (strcmp(adr,"file://")==0) ){ /* pas de proxy, ou non utilisable ici */
- soc=newhttp(adr,retour,-1,waitconnect);
- } else {
- soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect); // ouvrir sur le proxy α la place
- }
- } else {
- soc=newhttp(adr,NULL,-1,waitconnect);
- }
-
- // copier index socket retour
- if (retour) retour->soc=soc;
-
- // --------------------
- // court-circuit (court circuite aussi le proxy..)
- // LOCAL_SOCKET_ID est une pseudo-socket locale
- if (soc==LOCAL_SOCKET_ID) {
- retour->is_file=1; // fichier local
- if (mode==0) { // GET
-
- // Test en cas de file:///C|...
- if (!fexist(fconv(unescape_http(fil))))
- if (fexist(fconv(unescape_http(fil+1)))) {
- char tempo[HTS_URLMAXSIZE*2];
- strcpy(tempo,fil+1);
- strcpy(fil,tempo);
- }
-
- // Ouvrir
- retour->totalsize=fsize(fconv(unescape_http(fil))); // taille du fichier
- retour->msg[0]='\0';
- soc=INVALID_SOCKET;
- if (retour->totalsize<0)
- strcpy(retour->msg,"Unable to open file");
- else if (retour->totalsize==0)
- strcpy(retour->msg,"File empty");
- else {
- // Note: On passe par un FILE* (plus propre)
- //soc=open(fil,O_RDONLY,0); // en lecture seule!
- retour->fp=fopen(fconv(unescape_http(fil)),"rb"); // ouvrir
- if (retour->fp==NULL)
- soc=INVALID_SOCKET;
- else
- soc=LOCAL_SOCKET_ID;
- }
- retour->soc=soc;
- if (soc!=INVALID_SOCKET) {
- retour->statuscode=200; // OK
- strcpy(retour->msg,"OK");
- guess_httptype(retour->contenttype,fil);
- } else if (strnotempty(retour->msg)==0)
- strcpy(retour->msg,"Unable to open file");
- return soc; // renvoyer
- } else { // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
- strcpy(retour->msg,"Unexpected Head/Post local request");
- soc=INVALID_SOCKET; // erreur
- retour->soc=soc;
- return soc;
- }
- }
- // --------------------
-
- if (soc!=INVALID_SOCKET) {
- char rcvd[1100];
- rcvd[0]='\0';
- #if HDEBUG
- printf("Ok, connexion rΘussie, id=%d\n",soc);
- #endif
-
- // connectΘ?
- if (waitconnect) {
- http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
- }
-
- if (soc!=INVALID_SOCKET) {
-
- #if HDEBUG
- printf("Attente de la rΘponse:\n");
- #endif
-
- // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
- // et ensuite le corps
- // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
- // une rΘception standard pour rΘcupΘrer l'en tΩte
- if ((treat) && (waitconnect)) { // traiter (attendre!) en-tΩte
- // RΘception de la status line et de l'en-tΩte (norme RFC1945)
-
- // status-line α rΘcupΘrer
- finput(soc,rcvd,1024);
- if (strnotempty(rcvd)==0)
- finput(soc,rcvd,1024); // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
-
- // traiter status-line
- treatfirstline(retour,rcvd);
-
- #if HDEBUG
- printf("Status-Code=%d\n",retour->statuscode);
- #endif
-
- // en-tΩte
-
- // header // ** !attention! HTTP/0.9 non supportΘ
- do {
- finput(soc,rcvd,1024);
- #if HDEBUG
- printf(">%s\n",rcvd);
- #endif
- if (strnotempty(rcvd))
- treathead(NULL,NULL,NULL,retour,rcvd); // traiter
-
- } while(strnotempty(rcvd));
-
- //rcvsize=-1; // forCER CHARGEMENT INCONNU
-
- //if (retour)
- // retour->totalsize=rcvsize;
-
- } else { // si GET, on recevra l'en tΩte APRES
- //rcvsize=-1; // on ne connait pas la taille de l'en-tΩte
- if (retour)
- retour->totalsize=-1;
- }
-
- }
-
- }
-
- return soc;
- }
-
-
- // envoi d'une requΦte
- int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
- char buff[8192];
- //int use_11=0; // HTTP 1.1 utilisΘ
- int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
- char* search_tag=NULL;
- buff[0]='\0';
-
- // header Date
- //strcat(buff,"Date: ");
- //time_gmt_rfc822(buff); // obtenir l'heure au format rfc822
- //sendc("\n");
- //strcat(buff,buff);
-
- // possibilitΘ non documentΘe: >post: et >postfile:
- // si prΘsence d'un tag >post: alors executer un POST
- // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
- // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
- // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
- search_tag=strstr(fil,POSTTOK":");
- if (!search_tag) {
- search_tag=strstr(fil,POSTTOK"file:");
- if (search_tag) { // postfile
- if (mode==0) { // GET!
- FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
- if (fp) {
- char line[1100];
- char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
- linput(fp,line,1000);
- if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
- // selon que l'on a ou pas un proxy
- if (retour->req.proxy.active)
- sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
- else
- sprintf(buff,"%s %s %s\r\n",method,url,protocol);
- // lire le reste en brut
- fread(buff+strlen(buff),8000-strlen(buff),1,fp);
- }
- fclose(fp);
- }
- }
- }
- }
- // Fin postfile
-
- if (strnotempty(buff)==0) { // PAS POSTFILE
- // Type de requΦte?
- if ((search_tag) && (mode==0)) {
- strcat(buff,"POST ");
- } else if (mode==0) { // GET
- strcat(buff,"GET ");
- } else { // if (mode==1) {
- if (!retour->req.http11) // forcer HTTP/1.0
- strcat(buff,"GET "); // certains serveurs (cgi) buggent avec HEAD
- else
- strcat(buff,"HEAD ");
- }
-
- // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
- if (retour->req.proxy.active) {
- if (strncmp(adr,"ftp://",6)!=0) {
- #if HDEBUG
- printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
- #endif
- strcat(buff,"http://");
- strcat(buff,jump_identification(adr));
- } else { // ftp:// en proxy http
- #if HDEBUG
- printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
- #endif
- direct_url=1; // ne pas analyser user/pass
- strcat(buff,adr);
- }
- }
-
- // NOM DU FICHIER
- // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
- if (*fil!='/') strcat(buff,"/");
- {
- char tempo[HTS_URLMAXSIZE*2];
- tempo[0]='\0';
- if (search_tag)
- strncat(tempo,fil,(int) search_tag -(int) fil);
- else
- strcpy(tempo,fil);
- escape_check_url(tempo);
- strcat(buff,tempo); // avec Θchappement
- }
-
- // protocole
- if (!retour->req.http11) { // forcer HTTP/1.0
- //use_11=0;
- strcat(buff," HTTP/1.0\x0d\x0a");
- } else { // RequΦte 1.1
- //use_11=1;
- strcat(buff," HTTP/1.1\x0d\x0a");
- }
-
- /* supplemental data */
- if (xsend) strcat(buff,xsend); // Θventuelles autres lignes
-
- // tester proxy authentication
- if (retour->req.proxy.active) {
- char* a=jump_identification(retour->req.proxy.name);
- if (a!=retour->req.proxy.name) { // et hop, authentification proxy!
- char autorisation[1100];
- char user_pass[256];
- autorisation[0]=user_pass[0]='\0';
- //
- strncat(user_pass,retour->req.proxy.name,(int) a - (int) retour->req.proxy.name - 1);
- strcpy(user_pass,unescape_http(user_pass));
- code64(user_pass,autorisation);
- strcat(buff,"Proxy-Authorization: Basic ");
- strcat(buff,autorisation);
- strcat(buff,H_CRLF);
- #if HDEBUG
- printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
- #endif
- }
- }
-
- // Referer?
- if ((referer_adr) && (referer_fil)) { // existe
- if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) { // non vide
- if (strcmp(referer_adr,"file://")) { // PAS file://
- strcat(buff,"Referer: ");
- strcat(buff,"http://");
- strcat(buff,referer_adr);
- strcat(buff,referer_fil);
- strcat(buff,H_CRLF);
- }
- }
- }
-
- // POST?
- if (mode==0) { // GET!
- if (search_tag) {
- char clen[256];
- sprintf(clen,"Content-length: %d"H_CRLF,strlen(unescape_http(search_tag+strlen(POSTTOK)+1)));
- strcat(buff,clen);
- }
- }
-
- // gestion cookies?
- if (cookie) {
- char* b=cookie->data;
- int cook=0;
- int max_cookies=8;
- int max_size=2048;
- max_size+=strlen(buff);
- do {
- b=cookie_find(b,"",jump_identification(adr),fil); // prochain cookie satisfaisant aux conditions
- if (b) {
- max_cookies--;
- if (!cook) {
- strcat(buff,"Cookie: ");
- strcat(buff,"$Version=1; ");
- cook=1;
- } else
- strcat(buff,"; ");
- strcat(buff,cookie_get(b,5));
- strcat(buff,"=");
- strcat(buff,cookie_get(b,6));
- strcat(buff,"; $Path=");
- strcat(buff,cookie_get(b,2));
- b=cookie_nextfield(b);
- }
- } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
- if (cook) { // on a envoyΘ un (ou plusieurs) cookie?
- strcat(buff,H_CRLF);
- #if DEBUG_COOK
- printf("Header:\n%s\n",buff);
- #endif
- }
- }
-
- // connection close?
- //if (use_11) // Si on envoie une requΦte 1.1, prΘciser qu'on ne veut pas de keep-alive!!
- strcat(buff,"Connection: close"H_CRLF);
-
- //strcat(buff,"Referer: http://");ppp
- //strcat(buff,adr);
- //strcat(buff,"\n");
-
- // gΘrer le keep-alive (garder socket)
- //strcat(buff,"Connection: Keep-Alive\n");
-
- {
- char* real_adr=jump_identification(adr);
- //if ((use_11) || (retour->user_agent_send)) { // Pour le 1.1 on utilise un Host:
- if (!direct_url) { // pas ftp:// par exemple
- //if (!retour->req.proxy.active) {
- strcat(buff,"Host: "); strcat(buff,real_adr); strcat(buff,H_CRLF);
- //}
- }
- //}
-
- // PrΘsence d'un user-agent?
- if (retour->req.user_agent_send) { // ohh un user-agent
- char s[256];
- // HyperTextSeeker/"HTSVERSION
- sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
- strcat(buff,s);
-
- // pour les serveurs difficiles
- strcat(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"H_CRLF);
- if (strnotempty(retour->req.lang_iso)) {
- strcat(buff,"Accept-Language: "); strcat(buff,retour->req.lang_iso); strcat(buff,H_CRLF);
- }
- strcat(buff,"Accept-Charset: iso-8859-1, *"H_CRLF);
- strcat(buff,"Accept-Encoding: identity"H_CRLF); /* no compression */
- } else {
- strcat(buff,"Accept: */*"H_CRLF); // le minimum
- }
-
- /* Authentification */
- {
- char autorisation[1100];
- char* a;
- autorisation[0]='\0';
- if (real_adr != adr) { // ohh une authentification!
- if (!direct_url) { // pas ftp:// par exemple
- char user_pass[256];
- user_pass[0]='\0';
- strncat(user_pass,adr,(int) real_adr - (int) adr - 1);
- strcpy(user_pass,unescape_http(user_pass));
- code64(user_pass,autorisation);
- if (strcmp(fil,"/robots.txt")) /* pas robots.txt */
- bauth_add(cookie,real_adr,fil,autorisation);
- }
- } else if ( (a=bauth_check(cookie,real_adr,fil)) )
- strcpy(autorisation,a);
- /* On a une autorisation a donner? */
- if (strnotempty(autorisation)) {
- strcat(buff,"Authorization: Basic ");
- strcat(buff,autorisation);
- strcat(buff,H_CRLF);
- }
- }
-
- }
- //strcat(buff,"Accept-Language: en\n");
- //strcat(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
-
- // CRLF de fin d'en tΩte
- strcat(buff,H_CRLF);
-
- // donnΘes complΘmentaires?
- if (search_tag)
- if (mode==0) // GET!
- strcat(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
- }
-
- #if HDEBUG
- #endif
- if (_DEBUG_HEAD) {
- if (ioinfo) {
- fprintf(ioinfo,"Out:\r\n%s\r\n",buff);
- fflush(ioinfo);
- }
- } // Fin test pas postfile
- //
-
- // Envoi
- if (sendc(retour->soc,buff)<0) { // ERREUR, socket rompue?...
- //if (sendc(retour->soc,buff) != strlen(buff)) { // ERREUR, socket rompue?...
- deletesoc(retour->soc); // fermer tout de mΩme
- // et tenter de reconnecter
-
- strcpy(retour->msg,"Broken pipe");
- retour->soc=INVALID_SOCKET;
- /* non, α cause du poll connect()
- // si on avait une connexion proxy, tenter une connexion directe cette fois!
- retour->proxy.active=0;
- if (retour) {
- soc=newhttp(adr,retour->msg,-1,1);
- retour->soc=soc;
- }
- else {
- soc=newhttp(adr,NULL,-1,1);
- }
-
- // reconnectΘ?
- if (soc!=INVALID_SOCKET) {
- if (sendc(soc,buff)<0) { // NAN MARCHE PAS
- strcpy(retour->msg,"Can not write to a re-established socket connexion");
- deletesoc(soc); // fermer tout de mΩme
- soc=INVALID_SOCKET;
- }
-
- } else {
- strcpy(retour->msg,"Can not re-establish a socket connexion");
- }
- */
- }
-
- // RX'98
- return 0;
- }
-
-
-
-
- // traiter 1ere ligne d'en tΩte
- void treatfirstline(htsblk* retour,char* rcvd) {
- char* a=rcvd;
- // exemple:
- // HTTP/1.0 200 OK
- if (*a) {
- // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
- while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++; // Θpurer espaces au dΘbut
- // sauter HTTP/1.x
- while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;
- if (*a != '\0') {
- while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++; // Θpurer espaces
- if ((*a>='0') && (*a<='9')) {
- sscanf(a,"%d",&(retour->statuscode));
- // sauter 200
- while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;
- while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++; // Θpurer espaces
- if ((strlen(a) > 1) && (strlen(a) < 64) ) // message retour
- strcpy(retour->msg,a);
- else
- infostatuscode(retour->msg,retour->statuscode);
- // type MIME par dΘfaut
- strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
- } else { // pas de code!
- retour->statuscode=-1;
- strcpy(retour->msg,"Unknown response structure");
- }
- } else { // euhh??
- retour->statuscode=-1;
- strcpy(retour->msg,"Unknown response structure");
- }
- } else { // vide!
- retour->statuscode=-1;
- strcpy(retour->msg,"Empty reponse or internal error");
- }
- }
-
- // traiter ligne par ligne l'en tΩte
- // gestion des cookies
- void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
- int p;
- if ((p=strfield(rcvd,"Content-length:"))!=0) {
- #if HDEBUG
- printf("ok, Content-length: dΘtectΘ\n");
- #endif
- sscanf(rcvd+p,LLintP,&(retour->totalsize));
- }
- else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
- while(*(rcvd+p)==' ') p++; // sauter espaces
- if ((int) strlen(rcvd+p)<250) { // pas trop long?
- char tmp[256];
- char *a=NULL,*b=NULL;
- strcpy(tmp,rcvd+p);
- a=strstr(tmp,"filename=");
- if (a) {
- a+=strlen("filename=");
- while(is_space(*a)) a++;
- //a=strchr(a,'"');
- if (a) {
- char *c=NULL;
- //a++; /* jump " */
- while((c=strchr(a,'/'))) /* skip all / (see RFC2616) */
- a=c+1;
- //b=strchr(a+1,'"');
- b=a+strlen(a)-1;
- while(is_space(*b)) b--;
- b++;
- if (b) {
- *b='\0';
- if ((int) strlen(a) < 200) { // pas trop long?
- strcpy(retour->cdispo,a);
- }
- }
- }
- }
- }
- }
- else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
- while(*(rcvd+p)==' ') p++; // sauter espaces
- if ((int) strlen(rcvd+p)<64) { // pas trop long?
- //struct tm* tm_time=convert_time_rfc822(rcvd+p);
- strcpy(retour->lastmodified,rcvd+p);
- }
- }
- else if ((p=strfield(rcvd,"Date:"))!=0) {
- if (strnotempty(retour->lastmodified)==0) { /* pas encore de last-modified */
- while(*(rcvd+p)==' ') p++; // sauter espaces
- if ((int) strlen(rcvd+p)<64) { // pas trop long?
- //struct tm* tm_time=convert_time_rfc822(rcvd+p);
- strcpy(retour->lastmodified,rcvd+p);
- }
- }
- }
- else if ((p=strfield(rcvd,"Etag:"))!=0) { /* Etag */
- if (retour) {
- while(*(rcvd+p)==' ') p++; // sauter espaces
- if ((int) strlen(rcvd+p)<64) // pas trop long?
- strcpy(retour->etag,rcvd+p);
- else // erreur.. ignorer
- retour->etag[0]='\0';
- }
- }
- else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) { // chunk!
- retour->is_chunk=1; // chunked
- //retour->http11=2; // chunked
- #if HDEBUG
- printf("ok, Transfer-Encoding: dΘtectΘ\n");
- #endif
- }
- else if ((p=strfield(rcvd,"Content-type:"))!=0) {
- if (retour) {
- char tempo[1100];
- // Θviter les text/html; charset=foo
- {
- char* a=strchr(rcvd+p,';');
- if (a) *a='\0';
- }
- sscanf(rcvd+p,"%s",tempo);
- if (strlen(tempo)<64) // pas trop long!!
- strcpy(retour->contenttype,tempo);
- else
- strcpy(retour->contenttype,"application/octet-stream-unknown"); // erreur
- }
- }
- else if ((p=strfield(rcvd,"Location:"))!=0) {
- if (retour) {
- if (retour->location) {
- while(*(rcvd+p)==' ') p++; // sauter espaces
- if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE) // pas trop long?
- sscanf(rcvd+p,"%s",retour->location);
- else // erreur.. ignorer
- retour->location[0]='\0';
- }
- }
- }
- else if ((p=strfield(rcvd,"Connection: Keep-Alive"))!=0) {
- // non, pas de keep-alive! on dΘconnectera..
- }
- else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) { // params keep-alive
- // rien α faire
- }
- else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) { // ohh un cookie
- char* a = rcvd+p; // pointeur
- char domain[256]; // domaine cookie (.netscape.com)
- char path[256]; // chemin (/)
- char cook_name[256]; // nom cookie (MYCOOK)
- char cook_value[8192]; // valeur (ID=toto,S=1234)
- #if DEBUG_COOK
- printf("set-cookie detected\n");
- #endif
- while(*a) {
- char *token_st,*token_end;
- char *value_st,*value_end;
- char name[256];
- char value[8192];
- int next=0;
- name[0]=value[0]='\0';
- //
-
- // initialiser cookie lu actuellement
- if (adr)
- strcpy(domain,jump_identification(adr)); // domaine
- strcpy(path,"/"); // chemin (/)
- strcpy(cook_name,""); // nom cookie (MYCOOK)
- strcpy(cook_value,""); // valeur (ID=toto,S=1234)
- // boucler jusqu'au prochain cookie ou la fin
- do {
- char* start_loop=a;
- while(is_space(*a)) a++; // sauter espaces
- token_st=a; // dΘpart token
- while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++; // arrΩter si espace, point virgule
- token_end=a;
- while(is_space(*a)) a++; // sauter espaces
- if (*a=='=') { // name=value
- a++;
- while(is_space(*a)) a++; // sauter espaces
- value_st=a;
- while( (*a!=';') && (*a)) a++; // prochain ;
- //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++; // prochain " (et pas \")
- value_end=a;
- //if (*a==';') { // finit par un ;
- // vΘrifier dΘbordements
- if ( (((int) token_end - (int) token_st)<200) && (((int) value_end - (int) value_st)<8000)
- && (((int) token_end - (int) token_st)>0) && (((int) value_end - (int) value_st)>0) ) {
- name[0]='\0';
- value[0]='\0';
- strncat(name,token_st,(int) token_end - (int) token_st);
- strncat(value,value_st,(int) value_end - (int) value_st);
- #if DEBUG_COOK
- printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
- #endif
- if (strfield2(name,"domain")) {
- strcpy(domain,value);
- }
- else if (strfield2(name,"path")) {
- strcpy(path,value);
- }
- else if (strfield2(name,"max-age")) {
- // ignorΘ..
- }
- else if (strfield2(name,"expires")) {
- // ignorΘ..
- }
- else if (strfield2(name,"version")) {
- // ignorΘ..
- }
- else if (strfield2(name,"comment")) {
- // ignorΘ
- }
- else if (strfield2(name,"secure")) { // ne devrait pas arriver ici
- // ignorΘ
- }
- else {
- if (strnotempty(cook_name)==0) { // noter premier: nom et valeur cookie
- strcpy(cook_name,name);
- strcpy(cook_value,value);
- } else { // prochain cookie
- a=start_loop; // on devra recommencer α cette position
- next=1; // enregistrer
- }
- }
- }
- }
- if (!next) {
- while((*a!=';') && (*a)) a++; // prochain
- while(*a==';') a++; // sauter ;
- }
- } while((*a) && (!next));
- if (strnotempty(cook_name)) { // cookie?
- #if DEBUG_COOK
- printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
- #endif
- cookie_add(cookie,cook_name,cook_value,domain,path);
- }
- }
- }
- }
-
-
- // transforme le message statuscode en chaεne
- void infostatuscode(char* msg,int statuscode) {
- switch( statuscode) {
- // Erreurs HTTP, selon RFC
- case 100: strcpy( msg,"Continue"); break;
- case 101: strcpy( msg,"Switching Protocols"); break;
- case 200: strcpy( msg,"OK"); break;
- case 201: strcpy( msg,"Created"); break;
- case 202: strcpy( msg,"Accepted"); break;
- case 203: strcpy( msg,"Non-Authoritative Information"); break;
- case 204: strcpy( msg,"No Content"); break;
- case 205: strcpy( msg,"Reset Content"); break;
- case 206: strcpy( msg,"Partial Content"); break;
- case 300: strcpy( msg,"Multiple Choices"); break;
- case 301: strcpy( msg,"Moved Permanently"); break;
- case 302: strcpy( msg,"Moved Temporarily"); break;
- case 303: strcpy( msg,"See Other"); break;
- case 304: strcpy( msg,"Not Modified"); break;
- case 305: strcpy( msg,"Use Proxy"); break;
- case 306: strcpy( msg,"Undefined 306 error"); break;
- case 307: strcpy( msg,"Temporary Redirect"); break;
- case 400: strcpy( msg,"Bad Request"); break;
- case 401: strcpy( msg,"Unauthorized"); break;
- case 402: strcpy( msg,"Payment Required"); break;
- case 403: strcpy( msg,"Forbidden"); break;
- case 404: strcpy( msg,"Not Found"); break;
- case 405: strcpy( msg,"Method Not Allowed"); break;
- case 406: strcpy( msg,"Not Acceptable"); break;
- case 407: strcpy( msg,"Proxy Authentication Required"); break;
- case 408: strcpy( msg,"Request Time-out"); break;
- case 409: strcpy( msg,"Conflict"); break;
- case 410: strcpy( msg,"Gone"); break;
- case 411: strcpy( msg,"Length Required"); break;
- case 412: strcpy( msg,"Precondition Failed"); break;
- case 413: strcpy( msg,"Request Entity Too Large"); break;
- case 414: strcpy( msg,"Request-URI Too Large"); break;
- case 415: strcpy( msg,"Unsupported Media Type"); break;
- case 416: strcpy( msg,"Requested Range Not Satisfiable"); break;
- case 417: strcpy( msg,"Expectation Failed"); break;
- case 500: strcpy( msg,"Internal Server Error"); break;
- case 501: strcpy( msg,"Not Implemented"); break;
- case 502: strcpy( msg,"Bad Gateway"); break;
- case 503: strcpy( msg,"Service Unavailable"); break;
- case 504: strcpy( msg,"Gateway Time-out"); break;
- case 505: strcpy( msg,"HTTP Version Not Supported"); break;
- //
- default: if (strnotempty(msg)==0) strcpy( msg,"Unknown error"); break;
- }
- }
-
-
- // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
- htsblk xhttpget(char* adr,char* fil) {
- T_SOC soc;
- htsblk retour;
-
- bzero((char *)&retour, sizeof(htsblk));
- soc=http_fopen(adr,fil,&retour);
-
- if (soc!=INVALID_SOCKET) {
- http_fread(soc,&retour);
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("xhttpget: deletehttp\n");
- #endif
- if (retour.soc!=INVALID_SOCKET) deletehttp(&retour); // fermer
- retour.soc=INVALID_SOCKET;
- }
- return retour;
- }
-
- // variation sur un thΦme...
- // rΘceptionne uniquement un en-tΩte (HEAD)
- // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
- htsblk http_gethead(char* adr,char* fil) {
- T_SOC soc;
- htsblk retour;
-
- bzero((char *)&retour, sizeof(htsblk));
- soc=http_xfopen(1,0,1,NULL,adr,fil,&retour); // HEAD, pas de traitement en-tΩte
-
- if (soc!=INVALID_SOCKET) {
- http_fread(soc,&retour); // rΘception en-tΩte
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("http_gethead: deletehttp\n");
- #endif
- if (retour.soc!=INVALID_SOCKET) deletehttp(&retour); // fermer
- retour.soc=INVALID_SOCKET;
- }
- return retour;
- }
- // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
-
-
- // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
- // il ne reste plus qu'α lire les donnΘes
- // (pour HEAD le header est lu ici!)
- void http_fread(T_SOC soc,htsblk* retour) {
- //int bufl=TAILLE_BUFFER; // 8Ko de buffer
-
- if (retour) retour->soc=soc;
- if (soc!=INVALID_SOCKET) {
- // fonction de lecture d'une socket (plus propre)
- while(http_fread1(retour)!=-1);
- soc=retour->soc;
- if (retour->adr==NULL) {
- if (strnotempty(retour->msg)==0)
- sprintf(retour->msg,"Unable to read");
- return ; // erreur
- }
-
- #if HDEBUG
- printf("Ok, donnΘes reτues\n");
- #endif
-
- return ;
-
- }
-
- return ;
- }
-
- // lecture d'un bloc sur une socket (ou un fichier!)
- HTS_INLINE LLint http_fread1(htsblk* r) {
- //int bufl=TAILLE_BUFFER; // taille d'un buffer max.
- return http_xfread1(r,TAILLE_BUFFER);
- }
-
- // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
- // SI bufl=0 alors le buffer est censΘ Ωtre de 8kos, et on recoit caractΦres
- // par caractΦres en Θliminant les cr (ex: header)
- // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
- LLint http_xfread1(htsblk* r,int bufl) {
- int nl=-1;
-
- if (bufl>0) {
- if (!r->is_write) { // stocker en mΘmoire
- if (r->totalsize>0) { // totalsize dΘterminΘ ET ALLOUE
- if (r->adr==NULL) {
- r->adr=(char*) malloct((INTsys) r->totalsize + 1);
- r->size=0;
- }
- if (r->adr!=NULL) {
- // lecture
- nl=hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) ); /* NO 32 bit overlow possible here (no 4GB html!) */
- // nouvelle taille
- if (nl>0) r->size+=nl;
-
- if ((nl<=0) || (r->size >= r->totalsize))
- nl=-1; // break
-
- r->adr[r->size]='\0'; // caractΦre NULL en fin au cas o∙ l'on traite des HTML
- }
-
- } else { // inconnu..
- // rΘserver de la mΘmoire?
- if (r->adr==NULL) {
- #if HDEBUG
- printf("..alloc xfread\n");
- #endif
- r->adr=(char*) malloct(bufl + 1);
- r->size=0;
- }
- else {
- #if HDEBUG
- printf("..realloc xfread1\n");
- #endif
- r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
- }
-
- if (r->adr!=NULL) {
- // lecture
- nl=hts_read(r,r->adr+(int)r->size,bufl);
- if (nl>0) {
- // resize
- r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
- // nouvelle taille
- if (nl>0) r->size+=nl;
-
- if (r->adr) r->adr[r->size]='\0'; // octet nul
-
- } // sinon on a fini
- #if HDEBUG
- else
- printf("..end read (%d)\n",nl);
- #endif
- }
- #if HDEBUG
- else printf("..-> error\n");
- #endif
- }
-
- // pas de adr=erreur
- if (r->adr==NULL) nl=-1;
-
- } else { // stocker sur disque
- char* buff;
- buff=(char*) malloct(bufl);
- if (buff!=NULL) {
- // lecture
- nl=hts_read(r,buff,bufl);
- // nouvelle taille
- if (nl>0) {
- r->size+=nl;
- if ((int) fwrite(buff,1,nl,r->out)!=nl) {
- r->statuscode=-1;
- strcpy(r->msg,"Write error on disk");
- nl=-1;
- }
- }
-
- if ((nl<=0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
- nl=-1; // break
-
- // libΘrer bloc tempo
- freet(buff);
- } else nl=-1;
-
- // NON ce n'est pas notre r⌠le - et cela pose des problΦmes pour la rΘception en chunk
- /*
- //if (nl<=0) // fin
- //if (r->out!=NULL) { fclose(r->out); r->out=NULL; }
- */
- if (nl<=0) // fin
- if (r->out!=NULL) { fflush(r->out); }
-
-
- } // stockage disque ou mΘmoire
-
- } else { // rΘception d'un en-tΩte octet par octet
-
- if (r->adr==NULL) {
- r->adr=(char*) malloct(8192);
- r->size=0;
- }
-
- if (r->adr!=NULL) {
- // lecture
- nl=hts_read(r,r->adr+r->size,1);
- if (nl>0) {
- if (*(r->adr+r->size) != 13) // sauter caractΦres 13
- (r->size)++;
- *(r->adr+r->size)='\0'; // terminer par octet nul
- }
- if (r->size>=8190) {
- nl=-1; // break
- }
- }
- // pas de adr=erreur
- if (r->adr==NULL) nl=-1;
- }
- #if HDEBUG
- //printf("add to %d / %d\n",r->size,r->totalsize);
- #endif
- return ((nl>0)?0:-1);
- }
-
-
- // teste une adresse, et suit l'Θventuel chemin "moved"
- // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
- // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
- htsblk http_location(char* adr,char* fil,char* loc) {
- htsblk retour;
- int retry=0;
- int tryagain;
- // note: "RFC says"
- // 5 boucles au plus, on en teste au plus 8 ici
- // sinon abandon..
- do {
- tryagain=0;
- switch ((retour=http_test(adr,fil,loc)).statuscode) {
- case 200: break; // ok!
- case 301: case 302: case 303: case 307: // moved!
- // recalculer adr et fil!
- if (ident_url(loc,adr,fil)!=-1) {
- tryagain=1; // retenter
- retry++; // ..encore une fois
- }
- }
- } while((tryagain) && (retry<5+3));
- return retour;
- }
-
-
- // teste si une URL (validitΘ, header, taille)
- // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
- // en cas de moved xx, dans location
- // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
- // qui nous font poireauter 5 heures..) -> -2=timeout
- htsblk http_test(char* adr,char* fil,char* loc) {
- T_SOC soc;
- htsblk retour;
- //int rcvsize=-1;
- //char* rcv=NULL; // adresse de retour
- //int bufl=TAILLE_BUFFER; // 8Ko de buffer
- double tl;
- int timeout=30; // timeout pour un check (arbitraire) // **
-
- // pour abandonner un site trop lent
- tl=time_local();
-
- loc[0]='\0';
- bzero((char *)&retour, sizeof(htsblk)); // effacer
- retour.location=loc; // si non nul, contiendra l'adresse vΘritable en cas de moved xx
-
- //soc=http_fopen(adr,fil,&retour,NULL); // ouvrir, + header
-
- // on ouvre en head, et on traite l'en tΩte
- soc=http_xfopen(1,0,1,NULL,adr,fil,&retour); // ouvrir HEAD, + envoi header
-
- if (soc!=INVALID_SOCKET) {
- int e=0;
- // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
- do {
- if (http_xfread1(&retour,0)==-1)
- e=1;
- else {
- if (retour.adr!=NULL) {
- if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
- e=1;
- }
- }
-
- if (!e) {
- if ((time_local()-tl)>=timeout) {
- e=-1;
- }
- }
-
- } while (!e);
-
- if (e==1) {
- if (adr!=NULL) {
- int ptr=0;
- char rcvd[1100];
-
- // note: en gros recopie du traitement de back_wait()
- //
-
-
- // ----------------------------------------
- // traiter en-tΩte!
- // status-line α rΘcupΘrer
- ptr+=binput(retour.adr+ptr,rcvd,1024);
- if (strnotempty(rcvd)==0)
- ptr+=binput(retour.adr+ptr,rcvd,1024); // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
-
- // traiter status-line
- treatfirstline(&retour,rcvd);
-
- #if HDEBUG
- printf("(Buffer) Status-Code=%d\n",retour.statuscode);
- #endif
-
- // en-tΩte
-
- // header // ** !attention! HTTP/0.9 non supportΘ
- do {
- ptr+=binput(retour.adr+ptr,rcvd,1024);
- #if HDEBUG
- printf("(buffer)>%s\n",rcvd);
- #endif
- if (strnotempty(rcvd))
- treathead(NULL,NULL,NULL,&retour,rcvd); // traiter
-
- } while(strnotempty(rcvd));
- // ----------------------------------------
-
- // libΘrer mΘmoire
- if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
- }
- } else {
- retour.statuscode=-2;
- strcpy(retour.msg,"Timeout While Testing");
- }
-
-
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("http_test: deletehttp\n");
- #endif
- deletehttp(&retour);
- retour.soc=INVALID_SOCKET;
- }
- return retour;
- }
-
- // CrΘe un lien (http) vers une adresse internet iadr
- // retour: structure (adresse, taille, message si erreur (si !adr))
- // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
- int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {
- T_SOC soc; // descipteur de la socket
- char* iadr;
- // unsigned short int port;
-
- // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
- iadr = jump_identification(_iadr);
-
- // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
- // local.
- // utile pour les tests!
- //## if (iadr[0]!=lOCAL_CHAR) {
- if (strcmp(iadr,"file://")) { /* non fichier */
- struct sockaddr_in server;
- t_hostent* hp;
- // effacer structure
- bzero((char *)&server, sizeof(server));
-
- #if HDEBUG
- printf("gethostbyname\n");
- #endif
-
- // tester un Θventuel port
- if (port==-1) {
- char *a=strchr(iadr,':');
- port=80; // port par dΘfaut
- if (a) {
- char iadr2[HTS_URLMAXSIZE*2];
- int i=-1;
- iadr2[0]='\0';
- sscanf(a+1,"%d",&i);
- if (i!=-1) {
- port=(unsigned short int) i;
- }
-
- // adresse vΘritable (sans :xx)
- strncat(iadr2,iadr,(int) a-(int) iadr);
-
- // adresse sans le :xx
- hp = hts_gethostbyname(iadr2);
-
- } else {
-
- // adresse normale (port par dΘfaut par la suite)
- hp = hts_gethostbyname(iadr);
-
- }
-
- } else // port dΘfini
- hp = hts_gethostbyname(iadr);
-
-
- // Conversion iadr -> adresse
- // structure recevant le nom de l'h⌠te, etc
- //struct hostent *hp;
- if (hp == NULL) {
- #if DEBUG
- printf("erreur gethostbyname\n");
- #endif
- if (retour)
- if (retour->msg)
- strcpy(retour->msg,"Unable to get server's address");
- return INVALID_SOCKET;
- }
- // copie adresse
- bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
-
-
- // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
- #if HDEBUG
- printf("socket\n");
- #endif
- #if HTS_WIDE_DEBUG
- DEBUG_W("socket\n");
- #endif
- soc=socket(AF_INET,SOCK_STREAM,0);
- #if HTS_WIDE_DEBUG
- DEBUG_W("socket done\n");
- #endif
- if (soc==INVALID_SOCKET) {
- if (retour)
- if (retour->msg)
- strcpy(retour->msg,"Unable to create a socket");
- return INVALID_SOCKET; // erreur crΘation socket impossible
- }
- // structure: connexion au domaine internet, port 80 (ou autre)
- server.sin_family = AF_INET;
- server.sin_port = htons((unsigned short int) port);
- #if HDEBUG
- printf("==%d\n",soc);
- #endif
-
- // connexion non bloquante?
- if (!waitconnect ) {
- unsigned long p=1; // non bloquant
- #if HTS_WIN
- ioctlsocket(soc,FIONBIO,&p);
- #else
- ioctl(soc,FIONBIO,&p);
- #endif
- }
-
- // Connexion au serveur lui mΩme
- #if HDEBUG
- printf("connect\n");
- #endif
-
- #if HTS_WIDE_DEBUG
- DEBUG_W("connect\n");
- #endif
- #if HTS_WIN
- if (connect(soc, (const struct sockaddr FAR *)&server, sizeof(server)) != 0) {
- #else
- if (connect(soc, (struct sockaddr *)&server, sizeof(server)) == -1) {
- #endif
- // bloquant
- if (waitconnect) {
- #if HDEBUG
- printf("unable to connect!\n");
- #endif
- if (retour)
- if (retour->msg)
- strcpy(retour->msg,"Unable to connect to the server");
- deletesoc(soc);
- return INVALID_SOCKET;
- }
- }
- #if HTS_WIDE_DEBUG
- DEBUG_W("connect done\n");
- #endif
-
- #if HDEBUG
- printf("connexion Θtablie\n");
- #endif
-
- // A partir de maintenant, on peut envoyer et recevoir des donnΘes
- // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et
- // read(soc,adr,taille)
-
- } else { // on doit ouvrir un fichier local!
- // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
-
- soc=LOCAL_SOCKET_ID; // pseudo-socket locale..
- // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
-
- } // teste fichier local ou http
-
- return soc;
- }
-
-
-
- // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
- // retour=-1 si erreur.
- // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
- int ident_url(char* url,char* adr,char* fil) {
- char *p,*q;
- // traiter url
-
- // effacer adr et fil
- adr[0]=fil[0]='\0';
-
- p=strstr(url,"://"); // "scheme":// (RFC1945)
- if (p) {
- #if HDEBUG
- printf("protocol: %s\n",url);
- #endif
- // analyser le scheme
- if (strfield(url,"mailto")!=0) {
- return -1; // erreur non reconnu
- } else if (strfield(url,"news")!=0) {
- return -1; // erreur non reconnu
- } else if (strfield(url,"javascript")!=0) {
- return -1; // erreur non reconnu
- //
- } else if (strfield(url,"file")!=0) { // fichier local!! (pour les tests)
- p+=3;
- strcpy(adr,"file://");
- //## strcpy(adr,lOCAL_CHAR_STR); // indique un fichier local..
- //
- } else if (strfield(url,"http")!=0) { // HTTP
- p+=3;
- //
- } else if (strfield(url,"ftp")!=0) { // FTP
- //if (ftp_available()) {
- strcpy(adr,"ftp://"); // FTP!!
- //}
- p+=3;
- } else {
- // return -1;
- p+=3; // tant pis, beaucoup de ftp acceptent des requΦtes http
- // on peut tjs essayer!
- }
- } else {
- int n;
- p=url; // sans http://
- /* Bogus form:
- "http:foo.html" means "foo.html" */
- if ((n=strfield(url,"http:")) !=0 ) {
- p+=n;
- }
- }
-
- //## if (adr[0]!=lOCAL_CHAR) { // adresse normale http
- if (strcmp(adr,"file://")) { // PAS file://
- // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
- q=strchr(jump_identification(p),'/');
- if (q==0) q=p+strlen(p); // pointe sur \0
- // pointe sur le chemin, ex: index.html?query=recherche
-
- // chemin www... trop long!!
- if ( ( ((int) q)- ((int) p) ) > HTS_URLMAXSIZE) {
- //strcpy(retour.msg,"Path too long");
- return -1; // erreur
- }
-
- // recopier adresse www..
- strncat(adr,p, ((int) q) - ((int) p) );
- // *( adr+( ((int) q) - ((int) p) ) )=0; // faut arrΩter la fumette!
- // recopier chemin /pub/..
- strcat(fil,q);
- if (strnotempty(fil)==0) // page par dΘfaut (/)
- strcat(fil,"/");
- // SECURITE:
- // simplifier url pour les ../
- fil_simplifie(fil);
- } else { // localhost file://
- int i;
- char* a;
- strcat(fil,p); // fichier local ; adr="#"
- a=strchr(fil,'?');
- if (a)
- *a='\0'; /* couper query (inutile pour file:// lors de la requΩte) */
- // filtrer les \\ -> / pour les fichiers DOS
- for(i=0;i<(int) strlen(fil);i++)
- if (fil[i]=='\\')
- fil[i]='/';
- }
-
- // nommer au besoin.. (non utilisΘ normalement)
- if (strnotempty(fil)==0)
- strcpy(fil,"default-index.html");
-
- // case insensitive pour adresse
- {
- char *a=jump_identification(adr);
- while(*a) {
- if ((*a>='A') && (*a<='Z'))
- *a+='a'-'A';
- a++;
- }
- }
-
- return 0;
- }
-
- // simplification des ../
- void fil_simplifie(char* f) {
- int i=0;
- int last=0;
- char* a;
-
- // Θliminer ../
- while (f[i]) {
-
- if (f[i]=='/') {
- if (f[i+1]=='.')
- if (f[i+2]=='.') // couper dernier rΘpertoire
- if (f[i+3]=='/') // Θviter les /tmp/..coolandlamedir/
- { // couper dernier rΘpertoire
- char tempo[HTS_URLMAXSIZE*2];
- tempo[0]='\0';
- //
- if (!last) /* can't go upper.. */
- strcpy(tempo,"/");
- else
- strncpy(tempo,f,last+1);
- tempo[last+1]='\0';
- strcat(tempo,f+i+4);
- strcpy(f,tempo); // remplacer
- i=-1; // recommencer
- last=0;
- }
-
- if (i>=0)
- last=i;
- else
- last=0;
- }
-
- i++;
- }
-
- // Θliminer ./
- while ( (a=strstr(f,"./")) ) {
- char tempo[HTS_URLMAXSIZE*2];
- tempo[0]='\0';
- strcpy(tempo,a+2);
- strcpy(a,tempo);
- }
- // delete all remaining ../ (potential threat)
- while ( (a=strstr(f,"../")) ) {
- char tempo[HTS_URLMAXSIZE*2];
- tempo[0]='\0';
- strcpy(tempo,a+3);
- strcpy(a,tempo);
- }
-
- }
-
-
- // fermer liaison fichier ou socket
- HTS_INLINE void deletehttp(htsblk* r) {
- #if HTS_DEBUG_CLOSESOCK
- char info[256];
- sprintf(info,"deletehttp: (htsblk*) %d\n",r);
- DEBUG_W2(info);
- #endif
- if (r->soc!=INVALID_SOCKET) {
- if (r->is_file) {
- if (r->fp)
- fclose(r->fp);
- r->fp=NULL;
- } else {
- if (r->soc!=LOCAL_SOCKET_ID)
- deletesoc(r->soc);
- }
- r->soc=INVALID_SOCKET;
- }
- }
-
- // fermer une socket
- HTS_INLINE void deletesoc(T_SOC soc) {
- if (soc!=INVALID_SOCKET) {
- // J'ai plantΘ.. pas de shutdown
- //#if HTS_WIDE_DEBUG
- // DEBUG_W("shutdown\n");
- //#endif
- // shutdown(soc,2); // shutdown
- //#if HTS_WIDE_DEBUG
- // DEBUG_W("shutdown done\n");
- //#endif
- // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
- #if HTS_WIDE_DEBUG
- DEBUG_W("close\n");
- #endif
- #if HTS_WIN
- closesocket(soc);
- #else
- close(soc);
- #endif
- #if HTS_WIDE_DEBUG
- DEBUG_W("close done\n");
- #endif
- }
- }
-
- // renvoi le nombre de secondes depuis 1970
- HTS_INLINE double time_local() {
- return ((double) time(NULL));
- }
-
- // number of millisec since 1970
- HTS_INLINE double mtime_local() {
- #ifndef HTS_DO_NOT_USE_FTIME
- struct timeb B;
- ftime( &B );
- return (double) ( ((double) B.time * (double) 1000.0)
- + ((double) B.millitm) );
- #else
- // not precise..
- return (double) ( ((double) time_local() * (double) 1000.0)
- + ((double) 0) );
- #endif
- }
-
- // convertit un nombre de secondes en temps (chaine)
- void sec2str(char *st,double t) {
- int j,h,m,s;
-
- j=(int) (t/(3600.0*24.0));
- t-=((double) j)*(3600.0*24.0);
- h=(int) (t/(3600.0));
- t-=((double) h)*3600.0;
- m=(int) (t/60.0);
- t-=((double) m)*60.0;
- s=(int) t;
-
- if (j>0)
- sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
- else if (h>0)
- sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
- else if (m>0)
- sprintf(st,"%d minutes %d seconds",m,s);
- else
- sprintf(st,"%d seconds",s);
- }
-
- // idem, plus court (chaine)
- void qsec2str(char *st,double t) {
- int j,h,m,s;
-
- j=(int) (t/(3600.0*24.0));
- t-=((double) j)*(3600.0*24.0);
- h=(int) (t/(3600.0));
- t-=((double) h)*3600.0;
- m=(int) (t/60.0);
- t-=((double) m)*60.0;
- s=(int) t;
-
- if (j>0)
- sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
- else if (h>0)
- sprintf(st,"%dh,%02dmin%02ds",h,m,s);
- else if (m>0)
- sprintf(st,"%dmin%02ds",m,s);
- else
- sprintf(st,"%ds",s);
- }
-
-
- // heure actuelle, GMT, format rfc (taille buffer 256o)
- void time_gmt_rfc822(char* s) {
- time_t tt;
- struct tm* A;
- tt=time(NULL);
- A=gmtime(&tt);
- if (A==NULL)
- A=localtime(&tt);
- time_rfc822(s,A);
- }
-
- // heure actuelle, format rfc (taille buffer 256o)
- void time_local_rfc822(char* s) {
- time_t tt;
- struct tm* A;
- tt=time(NULL);
- A=localtime(&tt);
- time_rfc822_local(s,A);
- }
-
- /* convertir une chaine en temps */
- struct tm* convert_time_rfc822(char* s) {
- static struct tm result;
- /* */
- char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
- char str[256];
- char* a;
- /* */
- int result_mm=-1;
- int result_dd=-1;
- int result_n1=-1;
- int result_n2=-1;
- int result_n3=-1;
- int result_n4=-1;
- /* */
- if ((int) strlen(s) > 200)
- return NULL;
- strcpy(str,s);
- hts_lowcase(str);
- /* Θliminer :,- */
- while( (a=strchr(str,'-')) ) *a=' ';
- while( (a=strchr(str,':')) ) *a=' ';
- while( (a=strchr(str,',')) ) *a=' ';
- /* tokeniser */
- a=str;
- while(*a) {
- char *first,*last;
- char tok[256];
- /* dΘcouper mot */
- while(*a==' ') a++; /* sauter espaces */
- first=a;
- while((*a) && (*a!=' ')) a++;
- last=a;
- tok[0]='\0';
- if (first!=last) {
- char* pos;
- strncat(tok,first,(int) last-(int) first);
- /* analyser */
- if ( (pos=strstr(months,tok)) ) { /* month always in letters */
- result_mm=((int) pos-(int) months)/4;
- } else {
- int number;
- if (sscanf(tok,"%d",&number) == 1) { /* number token */
- if (result_dd<0) /* day always first number */
- result_dd=number;
- else if (result_n1<0)
- result_n1=number;
- else if (result_n2<0)
- result_n2=number;
- else if (result_n3<0)
- result_n3=number;
- else if (result_n4<0)
- result_n4=number;
- } /* sinon, bruit de fond(+1GMT for exampel) */
- }
- }
- }
- if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
- if (result_n4>=1000) { /* Sun Nov 6 08:49:37 1994 */
- result.tm_year=result_n4-1900;
- result.tm_hour=result_n1;
- result.tm_min=result_n2;
- result.tm_sec=max(result_n3,0);
- } else { /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
- result.tm_hour=result_n2;
- result.tm_min=result_n3;
- result.tm_sec=max(result_n4,0);
- if (result_n1<=50) /* 00 means 2000 */
- result.tm_year=result_n1+100;
- else if (result_n1<1000) /* 99 means 1999 */
- result.tm_year=result_n1;
- else /* 2000 */
- result.tm_year=result_n1-1900;
- }
- result.tm_isdst=0; /* assume GMT */
- result.tm_yday=-1; /* don't know */
- result.tm_wday=-1; /* don't know */
- result.tm_mon=result_mm;
- result.tm_mday=result_dd;
- return &result;
- }
- return NULL;
- }
-
- /* sets file time. -1 if error */
- int set_filetime(char* file,struct tm* tm_time) {
- struct utimbuf tim;
- #ifndef HTS_DO_NOT_USE_FTIME
- struct timeb B;
- B.timezone=0;
- ftime( &B );
- tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60;
- #else
- // bogus time (GMT/local)..
- tim.actime=tim.modtime=mktime(tm_time);
- #endif
- return utime(file,&tim);
- }
-
- /* sets file time from RFC822 date+time, -1 if error*/
- int set_filetime_rfc822(char* file,char* date) {
- struct tm* tm_s=convert_time_rfc822(date);
- if (tm_s) {
- return set_filetime(file,tm_s);
- } else return -1;
- }
-
-
- // heure au format rfc (taille buffer 256o)
- HTS_INLINE void time_rfc822(char* s,struct tm * A) {
- strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
- }
-
- // heure locale au format rfc (taille buffer 256o)
- HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
- strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
- }
-
- // conversion en b,Kb,Mb
- char* int2bytes(LLint n) {
- static char buff[256];
- char** a=int2bytes2(n);
- strcpy(buff,a[0]);
- strcat(buff,a[1]);
- return buff;
- }
-
- // conversion en b/s,Kb/s,Mb/s
- char* int2bytessec(long int n) {
- static char buff[256];
- char** a=int2bytes2(n);
- strcpy(buff,a[0]);
- strcat(buff,a[1]);
- return concat(buff,"/s");
- }
-
- // conversion en b,Kb,Mb, nombre et type sΘparΘs
- // limite: 2.10^9.10^6B
- char** int2bytes2(LLint n) {
- static char buff1[256];
- static char buff2[32];
- static char* buffadr[2];
- if (n<1024) {
- sprintf(buff1,"%d",(int)n);
- strcpy(buff2,"B");
- } else if (n<(1024*1024)) {
- sprintf(buff1,"%d,%02d",(int)(n/1024),(int)((n%1024)*100)/1024);
- strcpy(buff2,"KB");
- } else {
- sprintf(buff1,"%d,%02d",(int)(n/(1024*1024)),(int)(((n%(1024*1024))*100)/(1024*1024)));
- strcpy(buff2,"MB");
- }
- buffadr[0]=buff1;
- buffadr[1]=buff2;
- return buffadr;
- }
-
-
- // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
- HTS_INLINE int sendc(T_SOC soc,char* s) {
- #if HDEBUG
- write(0,s,strlen(s));
- #endif
- //#if HTS_WIN
- return send(soc,s,strlen(s),0);
- //#else
- // return write(soc,s,strlen(s));
- //#endif
- }
-
-
- // Remplace read
- void finput(int fd,char* s,int max) {
- static char c;
- register int j=0;
- do {
- //c=fgetc(fp);
- if (read(fd,&c,1)<=0) {
- c=0;
- }
- if (c!=0) {
- switch(c) {
- case 10: c=0; break;
- case 13: break; // sauter ces caractΦres
- default: s[j++]=c; break;
- }
- }
- } while((c!=0) && (j<max-1));
- s[j++]='\0';
- }
-
- // lire ligne dans buffer, renvoi incrΘment α opΘrer sur l'adresse ensuite
- int binput(char* buff,char* s,int max) {
- static char c;
- register int j=0;
- register int i=0;
- if ((*buff)=='\0') { // fin du buffer
- s[0]='\0';
- return 0; // eof
- }
- do {
- //c=fgetc(fp);
- c=*(buff++); i++;
- if (c!=0) {
- switch(c) {
- case 10: c=0; break;
- case 13: break; // sauter ces caractΦres
- default: s[j++]=c; break;
- }
- }
- } while((c!=0) && (j<max-1));
- s[j++]='\0';
- return i;
- }
-
- // Remplace fscanf(fp,"%s",s)
- void linput(FILE* fp,char* s,int max) {
- register int c;
- register int j=0;
- do {
- c=fgetc(fp);
- if (c!=EOF) {
- switch(c) {
- case 13: break; // sauter CR
- case 10: c=-1; break;
- case 9: case 12: break; // sauter ces caractΦres
- default: s[j++]=(char) c; break;
- }
- }
- } while((c!=-1) && (c!=EOF) && (j<(max-1)));
- s[j++]='\0';
- }
- void linput_trim(FILE* fp,char* s,int max) {
- char* ls=(char*) malloc(max+2);
- if (ls) {
- char* a;
- // lire ligne
- linput(fp,ls,max);
- // sauter espaces et tabs en fin
- while((ls[strlen(ls)-1]==' ') || (ls[strlen(ls)-1]=='\t')) ls[strlen(ls)-1]='\0';
- // sauter espaces en dΘbut
- a=ls; while((*a==' ') || (*a=='\t')) a++;
- strcpy(s,a);
- //
- free(ls);
- }
- }
- void linput_cpp(FILE* fp,char* s,int max) {
- s[0]='\0';
- do {
- if (s[strlen(s)-1]=='\\') s[strlen(s)-1]='\0'; // couper \ final
- // lire ligne
- linput_trim(fp,s+strlen(s),max-strlen(s));
- } while((s[strlen(s)-1]=='\\') && ((int)strlen(s)<max));
- }
-
- // idem avec les car spΘciaux
- void rawlinput(FILE* fp,char* s,int max) {
- register int c;
- register int j=0;
- do {
- c=fgetc(fp);
- if (c!=EOF) {
- switch(c) {
- case 13: break; // sauter CR
- case 10: c=-1; break;
- default: s[j++]=(char) c; break;
- }
- }
- } while((c!=-1) && (c!=EOF) && (j<(max-1)));
- s[j++]='\0';
- }
-
-
- // compare le dΘbut de f avec s et retourne la position de la fin
- // 'A=a' (case insensitive)
- int strfield(const char* f,const char* s) {
- register int r=0;
- while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
- if (*s==0)
- return r;
- else
- return 0;
- }
-
- //cherche chaine, case insensitive
- char* strstrcase(char *s,char *o) {
- while((*s) && (strfield(s,o)==0)) s++;
- if (*s=='\0') return NULL;
- return s;
- }
-
-
- // le fichier est-il un fichier html?
- // 0 : non
- // 1 : oui
- // -1 : on sait pas
- // -2 : on sait pas, pas d'extension
- int ishtml(char* fil) {
- char *a;
-
- // patch pour les truc.html?Choix=toto
- if ( (a=strchr(fil,'?')) ) // paramΦtres?
- a--; // pointer juste avant le ?
- else
- a=fil+strlen(fil)-1; // pointer sur le dernier caractΦre
-
- if (*a=='/') return -1; // rΘpertoire, on sait pas!!
- //if (*a=='/') return 1; // ok rΘpertoire, html
-
- while ( (*a!='.') && (*a!='/') && ((int) a>(int) fil)) a--;
- if (*a=='.') { // a une extension
- a++; // pointer sur extension
- return ishtml_ext(a); // retour
- } else return -2; // indΘterminΘ, par exemple /truc
- }
-
- // idem, mais pour uniquement l'extension
- int ishtml_ext(char* a) {
- int html=0;
- //
- if (strfield2(a,"html")) html = 1;
- else if (strfield2(a,"htm")) html = 1;
- else if (strfield2(a,"shtml")) html = 1;
- else if (strfield2(a,"htmlx")) html = 1;
- else if (strfield2(a,"shtm")) html = 1;
- else if (strfield2(a,"htmx")) html = 1;
- //
- else if (strfield2(a,"asp")) html = -1;
- else if (strfield2(a,"cgi")) html = -1; // indΘterminΘ
- //
- // insuccΦs..
- else {
- if (is_knowntype(a))
- html = 0; // connu, non html (html ont ΘtΘ testΘs avant)
- else
- html = -1; // inconnu..
- }
- return html;
- }
-
- // error (404,500..)
- HTS_INLINE int ishttperror(int err) {
- switch (err/100) {
- case 4: case 5: return 1;
- break;
- }
- return 0;
- }
-
-
- // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant une identification
- char* jump_identification(char* source) {
- char *a,*b;
- // rechercher dernier @ (car parfois email transmise dans adresse!)
- // mais sauter ftp:// Θventuel
- a = jump_protocol(source);
- while( (b = strchr(a,'@')) ) {
- char* c;
- if ( (c=strchr(a,'/')) ) /* si un / est trouvΘ */
- if ((int) c < (int) b) /* avant le @ */
- return a; /* alors exit (http://www.foo.bar/1.html@A20) */
- a=b+1;
- }
- return a;
- }
-
- // retourner adr sans ftp://
- HTS_INLINE char* jump_protocol(char* source) {
- if (strncmp(source,"ftp://",6)==0)
- return source+6;
- else if (strncmp(source,"http://",7)==0)
- return source+7;
- /* bogus form: http:relative.html */
- else if (strncmp(source,"http:",5)==0)
- return source+5;
- return source;
- }
-
- // codage base 64 a vers b
- void code64(char* a,char* b) {
- int i1=0,i2=0,i3=0,i4=0;
- unsigned long store;
- int n;
- const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- b[0]='\0';
- while(*a) {
- // 24 bits
- n=1; store=0; store |= ((*a++) & 0xff);
- if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); }
- if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); }
- if (n==3) {
- i4=store & 63;
- i3=(store>>6) & 63;
- i2=(store>>12) & 63;
- i1=(store>>18) & 63;
- } else if (n==2) {
- store<<=2;
- i3=store & 63;
- i2=(store>>6) & 63;
- i1=(store>>12) & 63;
- } else {
- store<<=4;
- i2=store & 63;
- i1=(store>>6) & 63;
- }
-
- *b++ = _hts_base64[i1];
- *b++ = _hts_base64[i2];
- if (n>=2)
- *b++ = _hts_base64[i3];
- else
- *b++ = '=';
- if (n>=3)
- *b++ = _hts_base64[i4];
- else
- *b++ = '=';
- }
- *b++='\0';
- }
-
- // remplacer " par " etc..
- // buffer MAX 1Ko
- void unescape_amp(char* s) {
- while(*s) {
- if (*s=='&') {
- char* end=strchr(s,';');
- if ( ((int) end - (int) s) <= 8) {
- char c=0;
- if (strfield(s,"&"))
- c='&';
- else if (strfield(s,"°"))
- c='░';
- else if (strfield(s,">"))
- c='>';
- else if (strfield(s,"«"))
- c='\"';
- else if (strfield(s,"<"))
- c='<';
- else if (strfield(s," "))
- c=' ';
- else if (strfield(s,"""))
- c='\"';
- else if (strfield(s,"»"))
- c='\"';
- else if (strfield(s,""))
- c='-';
- else if (strfield(s,"˜"))
- c='~';
- else if (strfield(s,"&"))
- c='&';
- // remplacer?
- if (c) {
- char buff[HTS_URLMAXSIZE*2];
- buff[0]=c;
- strcpy(buff+1,end+1);
- strcpy(s,buff);
- }
- }
- }
- s++;
- }
- }
-
- // remplacer %20 par ' ', | par : etc..
- // buffer MAX 1Ko
- char* unescape_http(char* s) {
- static char tempo[HTS_URLMAXSIZE*2];
- int i,j=0;
- for (i=0;i<(int) strlen(s);i++) {
- if (s[i]=='%') {
- i++;
- tempo[j++]=(char) ehex(s+i);
- i++; // sauter 2 caractΦres finalement
- } else if (s[i]=='|') { // exemple: file:///C|Program%20Files...
- tempo[j++]=':';
- } else
- tempo[j++]=s[i];
- }
- tempo[j++]='\0';
- return tempo;
- }
-
- // remplacer " par %xx etc..
- // buffer MAX 1Ko
- void escape_spc_url(char* s) {
- x_escape_http(s,2);
- }
- // smith / john -> smith%20%2f%20john
- void escape_in_url(char* s) {
- x_escape_http(s,1);
- }
- void escape_check_url(char* s) {
- x_escape_http(s,0);
- }
- void x_escape_http(char* s,int mode) {
- while(*s) {
- int test=0;
- if (mode == 0)
- test=(strchr("\" ",*s)!=0);
- else if (mode==1) {
- // Safe (RFC2396)
- test=(strchr(";/?:@&=+$,",*s)!=0);
- // Safe for us..
- if (!test)
- test=(strchr(" %*<>#'\"\\",*s)!=0);
- // Escape >127 (much safer)
- if (!test)
- test=((((unsigned char)*s) > 127)?1:0);
- }
- else if (mode==2)
- test=(strchr(" ",*s)!=0); // n'escaper que espace
-
- if (test) {
- char buffer[HTS_URLMAXSIZE*2];
- int n;
- n=(int)(unsigned char) *s;
- strcpy(buffer,s+1);
- sprintf(s,"%%%02x",n);
- strcat(s,buffer);
- }
- s++;
- }
- }
-
-
- HTS_INLINE int ehexh(char c) {
- if ((c>='0') && (c<='9')) return c-'0';
- if ((c>='a') && (c<='f')) c-=('a'-'A');
- if ((c>='A') && (c<='F')) return (c-'A'+10);
- return 0;
- }
-
- HTS_INLINE int ehex(char* s) {
- return 16*ehexh(*s)+ehexh(*(s+1));
-
- }
-
- // concat, concatΦne deux chaines et renvoi le rΘsultat
- // permet d'allΘger grandement le code
- // il faut savoir qu'on ne peut mettre plus de 8 concat() dans une expression
- char* concat(const char* a,const char* b) {
- static char buff[8][HTS_URLMAXSIZE*2];
- static int rol;
- rol=((rol+1)%8); // roving pointer
- strcpy(buff[rol],a);
- if (b) strcat(buff[rol],b);
- return buff[rol];
- }
- // conversion fichier / -> antislash
- #if HTS_DOSNAME
- char* __fconv(char* a) {
- int i;
- for(i=0;i<(int) strlen(a);i++)
- if (a[i]=='/') // convertir
- a[i]='\\';
- return a;
- }
- char* fconcat(char* a,char* b) {
- return __fconv(concat(a,b));
- }
- char* fconv(char* a) {
- return __fconv(concat(a,""));
- }
- #endif
-
- /* / et \\ en / */
- char* __fslash(char* a) {
- int i;
- for(i=0;i<(int) strlen(a);i++)
- if (a[i]=='\\') // convertir
- a[i]='/';
- return a;
- }
- char* fslash(char* a) {
- return __fslash(concat(a,""));
- }
-
- // conversion minuscules, avec buffer
- char* convtolower(char* a) {
- static char buff[8][HTS_URLMAXSIZE*2];
- static int rol;
- rol=((rol+1)%8); // roving pointer
- strcpy(buff[rol],a);
- hts_lowcase(buff[rol]); // lower case
- return buff[rol];
- }
-
- // conversion en minuscules
- void hts_lowcase(char* s) {
- register int i;
- for(i=0;i<(int) strlen(s);i++)
- if ((s[i]>='A') && (s[i]<='Z'))
- s[i]+=('a'-'A');
- }
-
- // remplacer un caractΦre d'une chaεne dans une autre
- HTS_INLINE void hts_replace(char *s,char from,char to) {
- register char* a;
- while ((a=strchr(s,from))!=NULL) {
- *a=to;
- }
- }
-
-
- // caractΦre espace, guillemets, CR, LF etc..
- /* SECTION OPTIMISEE:
- #define is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
- #define is_realspace(c) (strchr(" \x0d\x0a\x09",c)!=NULL)
- */
- /*
- HTS_INLINE int is_space(char c) {
- if (c==' ') return 1; // spc
- if (c=='"') return 1; // quote
- if (c==10) return 1; // lf
- if (c==13) return 1; // cr
- if (c=='\'') return 1; // quote
- //if (c=='`') return 1; // backquote << non
- if (c==9) return 1; // tab
- return 0;
- }
- */
-
- // caractΦre espace, CR, LF, TAB
- /*
- HTS_INLINE int is_realspace(char c) {
- if (c==' ') return 1; // spc
- if (c==10) return 1; // lf
- if (c==13) return 1; // cr
- if (c==9) return 1; // tab
- return 0;
- }
- */
-
-
-
-
-
- // deviner type d'un fichier local..
- // ex: fil="toto.gif" -> s="image/gif"
- void guess_httptype(char *s,char *fil) {
- get_httptype(s,fil,1);
- }
- // idem
- // flag: 1 si toujours renvoyer un type
- void get_httptype(char *s,char *fil,int flag) {
- if (ishtml(fil)==1)
- strcpy(s,"text/html");
- else {
- char *a=fil+strlen(fil)-1;
- while ( (*a!='.') && (*a!='/') && (a>fil)) a--;
- if (*a=='.') {
- int ok=0;
- int j=0;
- a++;
- while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
- if (strfield2(hts_mime[j][1],a)) {
- if (hts_mime[j][0][0]!='*') { // Une correspondance existe
- strcpy(s,hts_mime[j][0]);
- ok=1;
- }
- }
- j++;
- }
-
- if (!ok) if (flag) sprintf(s,"application/%s",a);
- } else {
- if (flag) strcpy(s,"application/octet-stream");
- }
- }
- }
- // renvoyer extesion d'un type mime..
- // ex: "image/gif" -> gif
- void give_mimext(char *s,char *st) {
- int ok=0;
- int j=0;
- strcpy(s,"");
- while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
- if (strfield2(hts_mime[j][0],st)) {
- if (hts_mime[j][1][0]!='*') { // Une correspondance existe
- strcpy(s,hts_mime[j][1]);
- ok=1;
- }
- }
- j++;
- }
- }
- // extension connue?..
- int is_knowntype(char *fil) {
- int j=0;
- while(strnotempty(hts_mime[j][1])) {
- if (strfield2(hts_mime[j][1],fil)) {
- return 1;
- }
- j++;
- }
- return 0;
- }
- // extension : html,gif..
- char* get_ext(char *fil) {
- char *a=fil+strlen(fil)-1;
- while ( (*a!='.') && (*a!='/') && (a>fil)) a--;
- if (*a=='.')
- return a+1;
- else
- return NULL;
- }
-
- // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
- // connaissent pas le type
- int may_unknown(char* st) {
- int j=0;
- // types mΘdia
- if (may_be_hypertext_mime(st))
- return 1;
- while(strnotempty(hts_mime_keep[j])) {
- if (strfield2(hts_mime_keep[j],st)) { // trouvΘ
- return 1;
- }
- j++;
- }
- return 0;
- }
-
-
- // -- Utils fichiers
- /* Le fichier existe-t-il? (ou est-il HTS_ACCESSible?) */
- int fexist(char* s) {
- FILE* fp;
- if (strnotempty(s)==0) // nom vide: non trouvΘ
- return 0;
- fp=fopen(fconv(s),"rb");
- if (fp!=NULL) fclose(fp);
- return (fp!=NULL);
- }
-
- /* Taille d'un fichier, -1 si n'existe pas */
- /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
- /* Note: NOT YET READY FOR 64-bit */
- //LLint fsize(char* s) {
- int fsize(char* s) {
- /*
- #if HTS_WIN
- HANDLE hFile;
- DWORD dwSizeHigh = 0;
- DWORD dwSizeLow = 0;
- hFile = CreateFile(s,0,0,NULL,OPEN_EXISTING,0,NULL);
- if (hFile) {
- dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;
- CloseHandle(hFile);
- if (dwSizeLow != 0xFFFFFFFF)
- return (dwSizeLow & (dwSizeHigh<<32));
- else
- return -1;
- } else
- return -1;
- #else
- */
- FILE* fp;
- if (strnotempty(s)==0) // nom vide: erreur
- return -1;
- fp=fopen(fconv(s),"rb");
- if (fp!=NULL) {
- int i;
- fseek(fp,0,SEEK_END);
- i=ftell(fp);
- fclose(fp);
- return i;
- } else return -1;
- /*
- #endif
- */
- }
-
- int fpsize(FILE* fp) {
- int oldpos,size;
- if (!fp)
- return -1;
- oldpos=ftell(fp);
- fseek(fp,0,SEEK_END);
- size=ftell(fp);
- fseek(fp,oldpos,SEEK_SET);
- return size;
- }
-
-
- hts_stat_struct HTS_STAT;
- //LLint HTS_TOTAL_RECV = 0; // flux entrant reτu
- //int HTS_TOTAL_RECV_STATE = 0; // status: 0 tout va bien 1: ralentir un peu 2: ralentir 3: beaucoup
- void HTS_TOTAL_RECV_CHECK(int var) {
- if (HTS_STAT.HTS_TOTAL_RECV_STATE) {
- if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) {
- var = min(var,32);
- Sleep(250);
- } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) {
- var = min(var,256);
- Sleep(100);
- } else {
- var/=2;
- if (var<=0) var=1;
- Sleep(50);
- }
- }
- }
-
- // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
- HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
- register int retour;
- // return read(soc,buff,size);
- if (r->is_file) {
- #if HTS_WIDE_DEBUG
- DEBUG_W("read\n");
- #endif
- if (r->fp)
- retour=fread(buff,1,size,r->fp);
- else
- retour=-1;
- } else {
- #if HTS_WIDE_DEBUG
- DEBUG_W("recv\n");
- if (r->soc==INVALID_SOCKET)
- printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
- #endif
- HTS_TOTAL_RECV_CHECK(size); // Diminuer au besoin si trop de donnΘes reτues
- retour=recv(r->soc,buff,size,0);
- if (retour>0) // compter flux entrant
- HTS_STAT.HTS_TOTAL_RECV+=retour;
- }
- #if HTS_WIDE_DEBUG
- DEBUG_W("recv/read done\n");
- #endif
- return retour;
- }
-
-
- // -- Gestion cache DNS --
- // 'RX98
- #if HTS_DNSCACHE
-
- // 'capsule' contenant uniquement le cache
- t_dnscache* _hts_cache() {
- static t_dnscache cache;
- return &cache;
- }
-
- // lock le cache dns pour tout opΘration d'ajout
- // plus prudent quand plusieurs threads peuvent Θcrire dedans..
- // -1: status? 0: libΘrer 1:locker
-
- /*
- Simple lock function for cache
-
- Return value: always 0
- Parameter:
- 1 wait for lock (mutex) available and lock it
- 0 unlock the mutex
- [-1 check if locked (always return 0 with mutex)]
- -999 initialize
- */
- #if USE_BEGINTHREAD
- int _hts_lockdns(int i) {
- static PTHREAD_LOCK_TYPE hMutex;
- return htsSetLock(&hMutex,i);
- }
- #else
- int _hts_lockdns(int i) {
- static int l=0;
- if (i>=0)
- l=i;
- return l;
- }
- #endif
-
- // routine pour le cache - retour optionnel α donner α chaque fois
- // NULL: nom non encore testΘ dans le cache
- // si h_length==0 alors le nom n'existe pas dans le dns
- t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
- // attendre que le cache dns soit prΩt
- while(_hts_lockdns(-1)); // attendre libΘration
- _hts_lockdns(1); // locker
-
- while(1) {
- if (strcmp(cache->iadr,iadr)==0) { // ok trouvΘ
- if (cache->host_length>0) { // entrΘe valide
- if (retour->h_addr)
- bcopy(cache->host_addr,(char *)retour->h_addr,cache->host_length);
- retour->h_length=cache->host_length;
- } else if (cache->host_length==0) { // en cours
- _hts_lockdns(0); // dΘlocker
- return NULL;
- } else { // erreur dans le dns, dΘja vΘrifiΘ
- if (retour->h_addr)
- retour->h_addr[0]='\0';
- retour->h_length=0; // erreur, n'existe pas
- }
- _hts_lockdns(0); // dΘlocker
- return retour;
- } else { // on a pas encore trouvΘ
- if (cache->n!=NULL) { // chercher encore
- cache=cache->n; // suivant!
- } else {
- _hts_lockdns(0); // dΘlocker
- return NULL; // non prΘsent
- }
- }
- }
- }
-
- // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
- // 0 non encore
- // 1 ok
- // 2 non prΘsent
- int hts_dnstest(char* _iadr) {
- static char iadr[HTS_URLMAXSIZE*2];
- t_dnscache* cache=_hts_cache(); // adresse du cache
-
- // sauter user:pass@ Θventuel
- strcpy(iadr,jump_identification(_iadr));
- // couper Θventuel :
- {
- char *a;
- if ( (a=strchr(iadr,':')) )
- *a='\0';
- }
-
- #if HTS_WIN
- if (inet_addr(iadr)!=INADDR_NONE) // numΘrique
- #else
- if (inet_addr(iadr)!=(in_addr_t) -1 ) // numΘrique
- #endif
- return 1;
-
- while(_hts_lockdns(-1)); // attendre libΘration
- _hts_lockdns(1); // locker
- while(1) {
- if (strcmp(cache->iadr,iadr)==0) { // ok trouvΘ
- _hts_lockdns(0); // dΘlocker
- return 1; // prΘsent!
- } else { // on a pas encore trouvΘ
- if (cache->n!=NULL) { // chercher encore
- cache=cache->n; // suivant!
- } else {
- _hts_lockdns(0); // dΘlocker
- return 2; // non prΘsent
- }
- }
- }
- }
-
- // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
- t_hostent* hts_gethostbyname(char* _iadr) {
- static char iadr[HTS_URLMAXSIZE*2];
- static t_hostent host;
- static char adr[HTS_URLMAXSIZE*2]=""; // buffer adr pour host
- static char* he[2];
- static unsigned long inetaddr;
- //
- t_dnscache* cache=_hts_cache(); // adresse du cache
- t_hostent* hp;
-
- strcpy(iadr,jump_identification(_iadr));
- // couper Θventuel :
- {
- char *a;
- if ( (a=strchr(adr,':')) )
- *a='\0';
- }
-
- // effacer structure de retour, crΘer nouvelle
- bzero((char *)&host,sizeof(t_hostent));
- host.h_addr_list=he;
- he[0]=adr;
- he[1]=NULL;
- host.h_length=0;
- cache->iadr[0]='*';
- cache->iadr[1]='\0';
-
- /* get IP from the dns cache */
- hp = _hts_ghbn(cache,iadr,&host);
- if (hp) {
- if (hp->h_length>0)
- return hp;
- else
- return NULL; // entrΘe erronΘe (erreur DNS) dans le DNS
- } else { // non prΘsent dans le cache dns, tester
- t_dnscache* c=cache;
- while(c->n) c=c->n; // calculer queue
-
- #if HTS_WIDE_DEBUG
- DEBUG_W("gethostbyname\n");
- #endif
- #if HDEBUG
- printf("gethostbyname (not in cache)\n");
- #endif
- {
- #if HTS_WIN
- if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
- #else
- if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
- #endif
- #if DEBUGDNS
- printf("resolving (not cached) %s\n",iadr);
- #endif
- hp=gethostbyname(iadr); // calculer IP host
- } else { // numΘrique, convertir sans passer par le dns
- host.h_addr=(char*) &inetaddr;
- host.h_length=4;
- hp=&host;
- }
- }
- #if HTS_WIDE_DEBUG
- DEBUG_W("gethostbyname done\n");
- #endif
- cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
- if (cache->n!=NULL) {
- strcpy(cache->n->iadr,iadr);
- if (hp!=NULL) {
- bcopy(hp->h_addr,cache->n->host_addr,hp->h_length);
- cache->n->host_length=hp->h_length;
- } else {
- cache->n->host_addr[0]='\0';
- cache->n->host_length=0; // non existant dans le dns
- }
- cache->n->n=NULL;
- return hp;
- } else { // on peut pas noter, mais on peut renvoyer le rΘsultat
- return hp;
- }
- } // retour hp du cache
- }
-
- #else
- HTS_INLINE t_hostent* hts_gethostbyname(char* iadr) {
- t_hostent* retour;
- #if HTS_WIDE_DEBUG
- DEBUG_W("gethostbyname (2)\n");
- #endif
- #if DEBUGDNS
- printf("blocking method gethostbyname() in progress for %s\n",iadr);
- #endif
- retour=gethostbyname(jump_identification(iadr));
- #if HTS_WIDE_DEBUG
- DEBUG_W("gethostbyname (2) done\n");
- #endif
- return retour;
- }
- #endif
-
-
- // --- Tracage des mallocs() ---
- #if HTS_TRACE_MALLOC
- typedef struct _mlink {
- void* adr;
- int len;
- int id;
- struct _mlink* next;
- } mlink;
- mlink trmalloc = {NULL,0,0,NULL};
- int trmalloc_id=0;
-
- HTS_INLINE void* hts_malloc(size_t len,size_t len2) {
- mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
- void* r = NULL;
- if (lnk) {
- if (len2)
- r = calloc(len,len2);
- else
- r = malloc(len);
- if (r) {
- lnk->adr=r;
- if (len2)
- lnk->len=len*len2;
- else
- lnk->len=len;
- lnk->id=trmalloc_id++;
- lnk->next=trmalloc.next;
- trmalloc.next=lnk;
- #if MEMDEBUG
- //printf("malloc: %d\n",r);
- #endif
- } else free(lnk);
- }
- return r;
- }
- HTS_INLINE void hts_free(void* adr) {
- mlink* lnk = &trmalloc;
- if (!adr) {
- #if MEMDEBUG
- printf("* unexpected free() error at %d\n",adr);
- #endif
- return;
- }
- do {
- if (lnk->next->adr==adr) {
- mlink* blk_free=lnk->next;
- #if 1
- lnk->next=lnk->next->next;
- free((void*) blk_free);
- #else
- #if MEMDEBUG
- if (blk_free->id==-1) {
- printf("* memory has already been freed: %d (id=%d)\n",blk_free->adr,blk_free->id);
- }
- #endif
- blk_free->id=-1;
- #endif
- free(adr);
- #if MEMDEBUG
- //printf("free: %d (id=%d)\n",blk_free->adr,blk_free->id);
- #endif
- return;
- }
- lnk=lnk->next;
- } while(lnk->next != NULL);
- #if MEMDEBUG
- printf("* unexpected free() error at %d\n",adr);
- #endif
- free(adr);
- }
- HTS_INLINE void* hts_realloc(void* adr,size_t len) {
- mlink* lnk = &trmalloc;
- do {
- if (lnk->next->adr==adr) {
- adr = realloc(adr,len);
- lnk->next->adr = adr;
- lnk->next->len = len;
- #if MEMDEBUG
- //printf("realloc: %d (id=%d)\n",lnk->next->adr,lnk->next->id);
- #endif
- return adr;
- }
- lnk=lnk->next;
- } while(lnk->next != NULL);
- #if MEMDEBUG
- printf("* unexpected realloc() error at %d\n",adr);
- #endif
- return realloc(adr,len);
- }
- // check the malloct() and calloct() trace stack
- void hts_freeall() {
- while(trmalloc.next) {
- #if MEMDEBUG
- printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
- #endif
- if (trmalloc.next->id != -1) {
- freet(trmalloc.next->adr);
- }
- }
- }
- #endif
-
-
- // -- divers //
-
- // cut path and project name
- // patch also initial path
- void cut_path(char* fullpath,char* path,char* pname) {
- path[0]=pname[0]='\0';
- if (strnotempty(fullpath)) {
- if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
- fullpath[strlen(fullpath)-1]='\0';
- if (strlen(fullpath)>1) {
- char* a;
- while( (a=strchr(fullpath,'\\')) ) *a='/'; // remplacer par /
- a=fullpath+strlen(fullpath)-2;
- while( (*a!='/') && ((int) a > (int) fullpath)) a--;
- if (*a=='/') a++;
- strcpy(pname,a);
- strncat(path,fullpath,(int) a-(int) fullpath);
- }
- }
- }
-
-
-
- // -- Gestion protocole ftp --
-
- #if HTS_WIN
- int ftp_available() {
- return 1;
- }
- #else
- int ftp_available() {
- return 1; // ok!
- //return 0; // SOUS UNIX, PROBLEMES
- }
- #endif
-
-
- // Fin
-
-